use std::cell::RefCell;
use std::io::{self, Write};
use std::rc::Rc;

use crate::diagnostics::{DiagnosticBag, DiagnosticBagCell, DiagnosticsPrinter, SourceText};
use crate::evaluator::ASTEvaluator;
use crate::lexer::Lexer;
use crate::parser::Parser;
use crate::LEVEL_MARK;

pub fn start() {
  let mut input = String::new();
  let mut stdout = io::stdout();
  let stdin = io::stdin();
  loop {
    write!(stdout, "> ").expect("Should have written prompt string >");

    stdout.flush().unwrap();
    stdin.read_line(&mut input).expect("fail to read stdin");

    // if input.len() == 0 {
    if input.is_empty() {
      break;
    }

    let text = SourceText::new(input.clone());

    let mut lexer = Lexer::new(input.as_str());
    let tokens = lexer.tokenizes();
    if LEVEL_MARK {
      for token in &tokens {
        writeln!(stdout, "{token:?}").expect("Token should have been written");
      }
    }

    // println!("---------------------分割线------------------------");

    let diagnostics_bag: DiagnosticBagCell = Rc::new(RefCell::new(DiagnosticBag::new()));

    let mut parser = Parser::new(tokens, Rc::clone(&diagnostics_bag));
    let ast = parser.print_ast();

    let diagnostics_binding = diagnostics_bag.borrow();
    // if diagnostics_binding.diagnostics.len() > 0 {
    if !diagnostics_binding.diagnostics.is_empty() {
      let diagnostics_printer = DiagnosticsPrinter::new(&text, &diagnostics_binding.diagnostics);
      diagnostics_printer.print();
      return;
    }
    // println!("---------------------分割线------------------------");

    let eval = ASTEvaluator::new();
    let result = eval.print_result(ast);
    println!("Result: {:?}", result);

    input.clear();
  }
}

pub fn start1() {
  io::stdin().lines().for_each(|line| {
    if let Ok(line) = line {
      let mut lexer = Lexer::new(line.as_str());

      let tokens = lexer.tokenizes();
      for token in &tokens {
        writeln!(io::stdout(), "{token:?}").expect("Token should have been written");
      }
    }
  });
}
